import BaseAssembler from "./BaseAssembler";
import Flexible, { ESplitType } from "./Flexible";
import { InitIndicesToContinousQuad } from "./Utils";


export default class FoldAssembler extends BaseAssembler {

    // private static 

    //  vx  quad    face    indices
    //  4   1       2       6
    //  6   2       4       12
    //  8   3       6       18
    //  10  4       8       24

    // quad = (vx - 2) / 2
    // face = vx - 2
    // indices = face * 3

    private static FloatsPerVert = 5;
    private static VerticesCount = 6;
    private static IndicesCount = (FoldAssembler.VerticesCount - 2) * 3;

    private static PositionOffset = 0;
    private static UVOffset = 2;
    private static ColorOffset = 4;

    private _vertices:Float32Array;
    private _indices:Uint16Array;
    private _verticesByUInt:Uint32Array;

    // private _edge:Array<number> = [];
    // private _splitA:number;
    // private _splitB:number;
    private _localSpecA:number;
    private _localSpecB:number;
    private _localSeq:Array<number> = [];


    get floatCount():number {
        return FoldAssembler.FloatsPerVert * FoldAssembler.VerticesCount;
    }

    get indexCount():number {
        // return (FoldAssembler.VerticesCount - 2) * 3;
        return FoldAssembler.IndicesCount;
    }

    constructor() {
        super();

        let vertices = new Float32Array(this.floatCount);
        let indices = new Uint16Array(this.indexCount);
        InitIndicesToContinousQuad(indices);

        let vertByUnit = new Uint32Array(vertices.buffer, 0, vertices.length);

        this._vertices = vertices;
        this._indices = indices;
        this._verticesByUInt = vertByUnit;
    }

    // private buildIndices(indices) {
    //     let count = indices.length / 6;
    //     for (let i = 0, idx = 0; i < count; i++) {
    //         let vertextID = i * 2;

    //         indices[idx++] = vertextID;
    //         indices[idx++] = vertextID + 2;
    //         indices[idx++] = vertextID + 1;

    //         indices[idx++] = vertextID + 2;
    //         indices[idx++] = vertextID + 3;
    //         indices[idx++] = vertextID + 1;
    //     }
    // }

    updateRenderData(comp:Flexible) {
        this.packToDynamicAtlas(comp, comp.spriteFrame);

        let percent:number = comp.splitPercent;
        let type = comp.splitType;

        this._updatePosition(comp, type, percent);
        this._updateUV(comp, type, percent);
    }

    updateColor (comp:Flexible, color) {
        let uintVerts = this._verticesByUInt ;
        if (!uintVerts) return;
        color = color != null ? color : comp.node.color['_val'];
        for (let i = FoldAssembler.ColorOffset, l = uintVerts.length; i < l; i += FoldAssembler.FloatsPerVert) {
            uintVerts[i] = color;
        }
    }

    private _transformToWorld(){

    }

    private _updatePosition(comp:Flexible, type:ESplitType, percent:number) {
        let node = comp.node;
        let cw = node.width, ch = node.height;
        let appx = node.anchorX * cw, appy = node.anchorY * ch;
        // let appx = node.width >> 1, appy = node.height >> 1;
        let l = -appx, b = -appy, r = cw - appx, t = ch - appy;
        
        let offset = FoldAssembler.PositionOffset;
        let verts = this._vertices;
        switch(type) {
            case ESplitType.Horizontal: {
                let s = b + ch * percent;

                verts[offset] = r;
                verts[offset+1] = b;
                offset += FoldAssembler.FloatsPerVert;

                verts[offset] = l;
                verts[offset+1] = b;
                offset += FoldAssembler.FloatsPerVert;

                verts[offset] = r;
                verts[offset+1] = s;
                offset += FoldAssembler.FloatsPerVert;

                verts[offset] = l;
                verts[offset+1] = s;
                offset += FoldAssembler.FloatsPerVert;

                verts[offset] = r;
                verts[offset+1] = t;
                offset += FoldAssembler.FloatsPerVert;

                verts[offset] = l;
                verts[offset+1] = t;
                offset += FoldAssembler.FloatsPerVert;
            }
            break;

            case ESplitType.Vertical: {

                let a1 = cw * percent, a2 = cw - cw * percent;
                let b1 = a1 * 0.618, b2 = a2 * 0.618;

                let s = l + a1;

                let lCal = s + a1 * Math.cos(comp.radAPage);

                verts[offset] = lCal;
                verts[offset+1] = b + b1 * Math.sin(-comp.radAPage);
                offset += FoldAssembler.FloatsPerVert;

                verts[offset] = lCal;
                verts[offset+1] = t + b1 * Math.sin(comp.radAPage);
                offset += FoldAssembler.FloatsPerVert;

                verts[offset] = s;
                verts[offset+1] = b;
                offset += FoldAssembler.FloatsPerVert;

                verts[offset] = s;
                verts[offset+1] = t;
                offset += FoldAssembler.FloatsPerVert;

                let rCal = s + a2 * Math.cos(comp.radBPage);

                verts[offset] = rCal;
                verts[offset+1] = b + b2 * Math.sin(-comp.radBPage);
                offset += FoldAssembler.FloatsPerVert;

                verts[offset] = rCal;
                verts[offset+1] = t + b2 * Math.sin(comp.radBPage);;
                offset += FoldAssembler.FloatsPerVert;
            }
            break;
        }
    }

    // private _updatePosition(comp:Flexible, type:ESplitType, partCount:number) {
    //     let node = comp.node;
    //     let cw = node.width, ch = node.height;
    //     let appx = node.anchorX * cw, appy = node.anchorY * ch;
    //     let l = -appx, b = -appy, r = cw - appx, t = ch - appy;
        
    //     let offset = FoldAssembler.PositionOffset;
    //     let verts = this._vertices;
    //     switch(type) {
    //         case ESplitType.Horizontal: {
    //             let dx = cw / partCount, dy = ch;
    //             for(let i = 0; i <= partCount; i++) {
    //                 verts[offset] = l + i * dx;
    //                 verts[offset+1] = b;
    //                 offset += FoldAssembler.FloatsPerVert;

    //                 verts[offset] = l + i * dx;
    //                 verts[offset+1] = t;
    //                 offset += FoldAssembler.FloatsPerVert;
    //             }
    //         }
    //         break;

    //         case ESplitType.Vertical: {
    //             let dx = cw, dy = ch / partCount;
    //             for(let i = 0; i <= partCount; i++) {
    //                 verts[offset] = r
    //                 verts[offset+1] = b + i * dy;
    //                 offset += FoldAssembler.FloatsPerVert;

    //                 verts[offset] = l;
    //                 verts[offset+1] = b + i * dy;
    //                 offset += FoldAssembler.FloatsPerVert;
    //             }
    //         }
    //         break;
    //     }
    // }

    private _updateUV(comp:Flexible, type:ESplitType, percent:number) {
        let sf:cc.SpriteFrame = comp.spriteFrame;
        if(!sf) return;

        let uv = sf['uv'];
        let verts = this._vertices;
        let l = uv[0], r = uv[2], b = uv[1], t = uv[5];

        let tw = r - l;
        let th = t - b;

        let offset = FoldAssembler.UVOffset;
        switch(type) {
            case ESplitType.Horizontal: {
                // let th = t - b;
                // let ml = b + th * percent.x, mr = b + th * percent.y;
                let s = b + (t - b) * percent;

                verts[offset] = r;
                verts[offset+1] = b;
                offset += FoldAssembler.FloatsPerVert;

                verts[offset] = l;
                verts[offset+1] = b;
                offset += FoldAssembler.FloatsPerVert;

                verts[offset] = r;
                verts[offset+1] = s;
                offset += FoldAssembler.FloatsPerVert;

                verts[offset] = l;
                verts[offset+1] = s;
                offset += FoldAssembler.FloatsPerVert;

                verts[offset] = r;
                verts[offset+1] = t;
                offset += FoldAssembler.FloatsPerVert;

                verts[offset] = l;
                verts[offset+1] = t;
                offset += FoldAssembler.FloatsPerVert;
            }
            break;

            case ESplitType.Vertical: {
                // let tw = r - l;
                // let mb = l + tw * percent.x, mt = l + tw * percent.y;
                let s = l + (r - l) * percent;
                
                verts[offset] = l;
                verts[offset+1] = b;
                offset += FoldAssembler.FloatsPerVert;

                verts[offset] = l;
                verts[offset+1] = t;
                offset += FoldAssembler.FloatsPerVert;

                verts[offset] = s;
                verts[offset+1] = b;
                offset += FoldAssembler.FloatsPerVert;

                verts[offset] = s;
                verts[offset+1] = t;
                offset += FoldAssembler.FloatsPerVert;

                verts[offset] = r;
                verts[offset+1] = b;
                offset += FoldAssembler.FloatsPerVert;

                verts[offset] = r;
                verts[offset+1] = t;
                offset += FoldAssembler.FloatsPerVert;
            }
            break;
        }
        
    }

    fillBuffers (comp:Flexible, renderer:cc.renderer) {

        let buffer = this.getBuffer();
        let offsetInfo = buffer.request(FoldAssembler.VerticesCount, FoldAssembler.IndicesCount);

        let vData = this._vertices;
        let iData = this._indices;

        // buffer data may be realloc, need get reference after request.

        // fill vertices
        let vertexOffset = offsetInfo.byteOffset >> 2;
        let vbuf = buffer._vData;;

        if (vData.length + vertexOffset > vbuf.length) {
            vbuf.set(vData.subarray(0, vbuf.length - vertexOffset), vertexOffset);
        } else {
            vbuf.set(vData, vertexOffset);
        }

        // fill indices
        let ibuf = buffer._iData;
        let indiceOffset = offsetInfo.indiceOffset;
        let vertexId = offsetInfo.vertexOffset;
        for (let i = 0, l = iData.length; i < l; i++) {
            ibuf[indiceOffset++] = vertexId + iData[i];
        }
    }


    // getVfmt () {
    //     return vfmtPosUvColor;
    // }
}